package hr.pzrinscak.web;

import hr.pzrinscak.jpa.VacationRequest;
import hr.pzrinscak.service.JpaService;
import hr.pzrinscak.util.StaticUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class ProcessController {

    private final static Logger LOGGER = LoggerFactory.getLogger(ProcessController.class);

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private FormService formService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private JpaService jpaService;

    @PersistenceContext
    private EntityManager entityManager;


    @RequestMapping(value = "/process/list", method = RequestMethod.GET)
    @ResponseBody
    Map<String, Object> getProcessList(
            @RequestParam final int start,
            @RequestParam final int limit,
            @RequestParam(required=false) final String sort,
            @RequestParam(required=false) final String dir)
    {

        ProcessDefinitionQuery processQuery = repositoryService.createProcessDefinitionQuery();

        if (StringUtils.hasText(sort)) {
            if ("name".equals(sort)) {
                processQuery.orderByProcessDefinitionName();
            }

            if ("ASC".equals(dir)) {
                processQuery.asc();
            }
            else if ("DESC".equals(dir)){
                processQuery.desc();
            }
        }

        List<ProcessDefinition> processList = processQuery.latestVersion().listPage(start, limit);
        long total = processQuery.count();

        List<Map<String, Object>> returnProcessList = generateProcessListMap(processList);

        Map<String, Object> response = new HashMap<String, Object>(2);
        response.put("totalCount", total);
        response.put("processes", returnProcessList);

        return response;
    }

    @RequestMapping(value = "/process/instance/list", method = RequestMethod.GET)
    @ResponseBody
    Map<String, Object> getProcessInstanceList(
            @RequestParam final int start,
            @RequestParam final int limit,
            @RequestParam(required=false) final String sort,
            @RequestParam(required=false) final String dir)
    {

        ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();

        if (StringUtils.hasText(sort)) {
            if ("id".equals(sort)) {
                processInstanceQuery.orderByProcessInstanceId();
            }

            if ("ASC".equals(dir)) {
                processInstanceQuery.asc();
            }
            else if ("DESC".equals(dir)){
                processInstanceQuery.desc();
            }
        }

        List<ProcessInstance> processList = processInstanceQuery.listPage(start, limit);
        long total = processInstanceQuery.count();

        List<Map<String, Object>> returnProcessList = generateProcessInstanceListMap(processList);

        Map<String, Object> response = new HashMap<String, Object>(2);
        response.put("totalCount", total);
        response.put("processes", returnProcessList);

        return response;
    }

    @RequestMapping(value = "/process/instance/delete", method = RequestMethod.POST)
    @ResponseBody
    Map<String, Object> deleteProcessInstance(@RequestParam final String processInstanceId)
    {
        runtimeService.deleteProcessInstance(processInstanceId, "System!");

        Map<String, Object> response = new HashMap<String, Object>(2);
        response.put("success", true);
        response.put("message", "Submit success!");
        return response;
    }

    @RequestMapping(value = "/process/form", method = RequestMethod.GET)
    ModelAndView getProcessForm(final String formKey) {

        ModelAndView mav = new ModelAndView("process/" + formKey);
        return mav;
    }

    @RequestMapping(value = "/process/form", method = RequestMethod.POST)
    @ResponseBody
    Map<String, Object> submitProcessForm(@ModelAttribute("package") final VacationRequest vacationRequest, @RequestParam final Map<String, String> requestParameters) {

        String processDefinitionId = requestParameters.remove("processDefinitionId");

        jpaService.saveVacationRequest(vacationRequest,processDefinitionId);

        Map<String, Object> response = new HashMap<String, Object>(2);
        response.put("success", true);
        response.put("message", "Submit success!");

        return response;
    }

    private List<Map<String, Object>> generateProcessListMap(final List<ProcessDefinition> processList) {

        List<Map<String, Object>> returnProcessList = new ArrayList<Map<String,Object>>(processList.size());
        for (ProcessDefinition processDefinition : processList) {
            Map<String, Object> processMap = new HashMap<String, Object>();
            processMap.put("id", processDefinition.getId());
            processMap.put("key", processDefinition.getKey());
            processMap.put("name", processDefinition.getName());
            processMap.put("resourceName", processDefinition.getResourceName());
            processMap.put("version", processDefinition.getVersion());
            processMap.put("category", processDefinition.getCategory());
            processMap.put("deploymentId", processDefinition.getDeploymentId());
            processMap.put("formKey", formService.getStartFormData(processDefinition.getId()).getFormKey());
            returnProcessList.add(processMap);
        }
        return returnProcessList;
    }

    private List<Map<String, Object>> generateProcessInstanceListMap(final List<ProcessInstance> processList) {

        List<Map<String, Object>> returnProcessList = new ArrayList<Map<String,Object>>(processList.size());
        for (ProcessInstance processInstance : processList) {
            Map<String, Object> processMap = new HashMap<String, Object>();
            processMap.put("id", processInstance.getId());
            processMap.put("businessKey", processInstance.getBusinessKey());
            processMap.put("processDefinitionId", processInstance.getProcessDefinitionId());
            processMap.put("processInstanceId", processInstance.getProcessInstanceId());
            returnProcessList.add(processMap);
        }
        return returnProcessList;
    }
}
